home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / WASTE 1.2 / WASTE Demo ƒ / WEDemoFiles.c < prev    next >
Text File  |  1996-05-19  |  11KB  |  435 lines

  1. /*
  2.     WASTE Demo Project:
  3.     File Handling
  4.  
  5.     Copyright © 1993-1996 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __WEDEMOAPP__
  13. #include "WEDemoIntf.h"
  14. #endif
  15.  
  16. #ifndef __FOLDERS__
  17. #include <Folders.h>
  18. #endif
  19.  
  20. #define    kFileNotOpened    -1
  21.  
  22. OSErr ReadTextFile( const FSSpec *pFileSpec, WEReference we )
  23. {
  24.     short    dataForkRefNum = kFileNotOpened;
  25.     short    resForkRefNum = kFileNotOpened;
  26.     Handle    hText = nil;
  27.     Handle    hStyles = nil;
  28.     Handle    hSoup = nil;
  29.     Size    textSize;
  30.     OSErr    err;
  31.  
  32.     //    open the data fork with read-only permission
  33.     if ((err = FSpOpenDF(pFileSpec, fsRdPerm, &dataForkRefNum)) != noErr)
  34.         goto cleanup;
  35.  
  36.     //    get data fork size
  37.     if ((err = GetEOF(dataForkRefNum, &textSize)) != noErr)
  38.         goto cleanup;
  39.  
  40.     //    set the position in the file from where to start reading
  41.     if ((err = SetFPos(dataForkRefNum, fsFromStart, 0L)) != noErr)
  42.         goto cleanup;
  43.  
  44.     //    try to allocate a handle that large, use temporary memory if available
  45.     if ((err = NewHandleTemp(textSize, &hText)) != noErr)
  46.         goto cleanup;
  47.  
  48.     //    read in the text
  49.     HLock(hText);
  50.     err = FSRead(dataForkRefNum, &textSize, *hText);
  51.     HUnlock(hText);
  52.     if (err != noErr)
  53.         goto cleanup;
  54.  
  55.     //    see if the file has a resource fork
  56.     //    FSpOpenResFile will return -1 if it fails
  57.     if ( ( resForkRefNum = FSpOpenResFile( pFileSpec, fsRdPerm ) ) != kFileNotOpened )
  58.     {
  59.         //    look for a style scrap resource (get the first one; the resource ID doesn't matter)
  60.         if ((hStyles = Get1IndResource(kTypeStyles, 1)) != nil)
  61.         {
  62.             DetachResource(hStyles);
  63.         }
  64.  
  65.         //    look for a soup resource as well
  66.         if ((hSoup = Get1IndResource(kTypeSoup, 1)) != nil)
  67.         {
  68.             DetachResource(hSoup);
  69.         }
  70.     }
  71.  
  72.     //    insert the text into the WE record
  73.     HLock(hText);
  74.     if ((err = WEInsert(*hText, textSize, (StScrpHandle) hStyles, hSoup, we)) != noErr)
  75.         goto cleanup;
  76.  
  77.     //    set the insertion point at the beginning of the text
  78.     WESetSelection(0, 0, we);
  79.  
  80.     //    reset the WE instance modification count
  81.     WEResetModCount( we );
  82.  
  83. cleanup:
  84.     // display an alert box if anything went wrong
  85.     if (err != noErr)
  86.     {
  87.         ErrorAlert( err );
  88.     }
  89.  
  90.     ForgetHandle(&hText);
  91.     ForgetHandle(&hStyles);
  92.     ForgetHandle(&hSoup);
  93.  
  94.     if ( dataForkRefNum != kFileNotOpened )
  95.     {
  96.         FSClose(dataForkRefNum);
  97.         dataForkRefNum = kFileNotOpened;
  98.     }
  99.  
  100.     if ( resForkRefNum != kFileNotOpened )
  101.     {
  102.         CloseResFile(resForkRefNum);
  103.         resForkRefNum = kFileNotOpened;
  104.     }
  105.  
  106.     return err;
  107. }
  108.  
  109. // I added a bunch of other functionality to WriteTextFile(), mostly to show how to use
  110. // temp files, check for locked files, etc. ( all along Apple's recommended way of
  111. // doing things.  - JCD
  112.  
  113. OSErr WriteTextFile( const FSSpec * pFileSpec, WEReference we )
  114. {
  115.     FInfo            fileInfo;
  116.     Size            textSize;
  117.     Boolean            replacing;
  118.     short            dataForkRefNum = kFileNotOpened;
  119.     short            resForkRefNum = kFileNotOpened;
  120.     Handle            hText = nil;
  121.     StScrpHandle    hStyles = nil;
  122.     WESoupHandle    hSoup = nil;
  123.     unsigned long    theTime;
  124.     Str255            tempFileName;
  125.     FSSpec            tempFileSpec;
  126.     short            tempVRef;        // volume reference # for the temp file
  127.     long            tempDirID;        // directory ID of the temp file
  128.     OSErr            err;
  129.  
  130.     //    will we be replacing an existing file?
  131.     err = FSpGetFInfo( pFileSpec, &fileInfo ) ;
  132.     if ( err == noErr )
  133.     {
  134.         replacing = true;
  135.     }
  136.     else if ( err == fnfErr )
  137.     {
  138.         replacing = false;
  139.     }
  140.     else
  141.     {
  142.         goto cleanup;
  143.     }
  144.  
  145.     // originally, Marco had it so that if the file already existed (replacing == true)
  146.     // then just can the original file and move along.  for the scope of this demo, that
  147.     // really is ok, but generally speaking, not the Apple-recommended way of doing things.
  148.     // since we know we're under (at least) System 7 (due to WASTE's need of it), we know
  149.     // we can use temporary files, so let us do so!
  150.  
  151.     // also, Marco didn't check for locked files (technically, if a file is locked from
  152.     // the Finder, you shouldn't be able to modify it).  let's check for that.
  153.  
  154.     // if the file currently exists (meaning it was saved at some time in the past, be it
  155.     // 5 minutes ago, or 5 days ago), there is a chance that it could be locked (from the
  156.     // Finder's "Get Info" window (or otherwise).  If the file is locked, you cannot
  157.     // save changes.  Therefore, if 'replacing' is true, we have to throw up a message
  158.     // saying that we can't do this, then exit.
  159.  
  160.     if ( replacing )
  161.     {
  162.         if ((err = FSpCheckObjectLock( pFileSpec )) != noErr)
  163.             goto cleanup;
  164.  
  165.         // create the temporary file name.  the name doesn't have to make sense, just
  166.         // be unique
  167.  
  168.         GetDateTime( &theTime );
  169.         NumToString( theTime, tempFileName );
  170.  
  171.         // find the temporary items folder on the file's volume; create it if necessary
  172.         // it is important that the temp folder (and the temp file) and the "original" target
  173.         // file be on the same volume; if not, FSpExchangeFiles will return diffVolErr (-1303)
  174.         // and won't work
  175.  
  176.         if ((err = FindFolder( pFileSpec->vRefNum, kTemporaryFolderType, kCreateFolder, &tempVRef, &tempDirID )) != noErr)
  177.             goto cleanup;
  178.  
  179.         // make an FSSpec for the temp file
  180.         err = FSMakeFSSpec( tempVRef, tempDirID, tempFileName, &tempFileSpec );
  181.         if ( (err != noErr) && (err != fnfErr ) )
  182.             goto cleanup;
  183.     }
  184.  
  185.     //    create a new file.  if we're replacing, make a temp file.  if it's a
  186.     //  new file from the onset, just create the file
  187.  
  188.     // should we allow people to choose the file to create?  i.e. create a TEXT
  189.     // file or a ttro file?  if you'd like to do this, you'll want to find this
  190.     // info out when calling CustomPutFile() and pass that info to this function
  191.  
  192.     if ( replacing )
  193.     {
  194.         FSpCreateResFile( &tempFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
  195.     }
  196.     else
  197.     {
  198.         FSpCreateResFile( pFileSpec, sigWASTEDemo, kTypeText, smSystemScript );
  199.     }
  200.  
  201.     if ((err = ResError()) != noErr)
  202.         goto cleanup;
  203.  
  204.     //  if replacing an old file, copy the old file information
  205.     if ( replacing )
  206.     {
  207.         if ( ( err = FSpSetFInfo( &tempFileSpec, &fileInfo ) ) != noErr )
  208.         {
  209.             goto cleanup;
  210.         }
  211.     }
  212.  
  213.     //    open the data fork for writing
  214.     if ( replacing )
  215.     {
  216.         err = FSpOpenDF( &tempFileSpec, fsRdWrPerm, &dataForkRefNum );
  217.     }
  218.     else
  219.     {
  220.         err = FSpOpenDF( pFileSpec, fsRdWrPerm, &dataForkRefNum );
  221.     }
  222.  
  223.     if ( err != noErr )
  224.     {
  225.         goto cleanup;
  226.     }
  227.  
  228.     //    set the end-of-file
  229.     if ( ( err = SetEOF( dataForkRefNum, 0 ) ) != noErr )
  230.     {
  231.         goto cleanup;
  232.     }
  233.  
  234.     //    set the position in the file to write from
  235.     if ( ( err = SetFPos( dataForkRefNum, fsFromStart, 0 ) ) != noErr )
  236.     {
  237.         goto cleanup;
  238.     }
  239.  
  240.     //    get the text handle from the WE instance
  241.     //    WEGetText returns the original handle, not a copy, so don't dispose of it!!
  242.     hText = WEGetText( we );
  243.     textSize = GetHandleSize( hText );
  244.  
  245.     //    write the text
  246.     HLock( hText );
  247.     err = FSWrite( dataForkRefNum, &textSize, *hText );
  248.     HUnlock( hText );
  249.  
  250.     if ( err != noErr )
  251.     {
  252.         goto cleanup;
  253.     }
  254.  
  255.     //    open the resource file for writing
  256.     if ( replacing )
  257.     {
  258.         resForkRefNum = FSpOpenResFile( &tempFileSpec, fsRdWrPerm );
  259.     }
  260.     else
  261.     {
  262.         resForkRefNum = FSpOpenResFile( pFileSpec, fsRdWrPerm );
  263.     }
  264.  
  265.     if ( ( err = ResError ( ) ) != noErr )
  266.     {
  267.         goto cleanup;
  268.     }
  269.  
  270.     //    allocate temporary handles to hold the style scrap and the soup
  271.     //    try tapping temporary memory since WECopyRange() could get huge
  272.     if ( ( err = NewHandleTemp( 0, (Handle *) &hStyles ) ) != noErr )
  273.     {
  274.         goto cleanup;
  275.     }
  276.     if ( ( err = NewHandleTemp( 0, (Handle *) &hSoup ) ) != noErr )
  277.     {
  278.         goto cleanup;
  279.     }
  280.  
  281.     //    create the style scrap and the soup
  282.     if ( ( err = WECopyRange( 0, LONG_MAX, nil, hStyles, hSoup, we ) ) != noErr )
  283.     {
  284.         goto cleanup;
  285.     }
  286.  
  287.     //    make them resource handles
  288.     AddResource( (Handle) hStyles, kTypeStyles, 128, "\p" );
  289.     if ( ( err = ResError ( ) ) != noErr )
  290.     {
  291.         goto cleanup;
  292.     }
  293.  
  294.     AddResource( (Handle) hSoup, kTypeSoup, 128, "\p" );
  295.     if ( ( err = ResError ( ) ) != noErr )
  296.     {
  297.         goto cleanup;
  298.     }
  299.  
  300.     //    write them to the resource file
  301.     ChangedResource( (Handle)hStyles );
  302.     WriteResource( (Handle)hStyles );
  303.     if ( ( err = ResError ( ) ) != noErr )
  304.     {
  305.         goto cleanup;
  306.     }
  307.  
  308.     ChangedResource( (Handle)hSoup );
  309.     WriteResource( (Handle)hSoup );
  310.     if ( ( err = ResError ( ) ) != noErr )
  311.     {
  312.         goto cleanup;
  313.     }
  314.  
  315.     //    "clean" this document by resetting the WE instance modification count
  316.     WEResetModCount( we );
  317.  
  318.     err = noErr;
  319.  
  320. cleanup:
  321.     // display an alert box if anything went wrong
  322.     if (err != noErr)
  323.     {
  324.         ErrorAlert( err );
  325.     }
  326.  
  327.     // remember, don't dispose the hText handle!
  328.     ForgetResource( (Handle *) &hStyles );
  329.     ForgetResource( (Handle *) &hSoup );
  330.  
  331.     if ( dataForkRefNum != kFileNotOpened )
  332.     {
  333.         FSClose( dataForkRefNum ) ;
  334.         dataForkRefNum = kFileNotOpened ;
  335.     }
  336.  
  337.     if ( resForkRefNum != kFileNotOpened )
  338.     {
  339.         CloseResFile( resForkRefNum ) ;
  340.         resForkRefNum = kFileNotOpened ;
  341.     }
  342.  
  343.     if ( replacing )
  344.     {
  345.         // update the disk with any unwritten data
  346.  
  347.         FlushVol( nil, tempFileSpec.vRefNum );
  348.  
  349.         // since we were replacing an existing file, let's now swap the original
  350.         // and the temp file.  let's hear it for safe saves.
  351.  
  352.         if ( ( err = FSpExchangeFiles( &tempFileSpec, pFileSpec ) ) != noErr )
  353.         {
  354.             // handle the error
  355.             return err;
  356.         }
  357.  
  358.         // can the temp file since we don't need it anymore
  359.  
  360.         err = FSpDelete( &tempFileSpec );
  361.         if ( err != noErr )
  362.         {
  363.             // handle the error
  364.  
  365.             return err;
  366.         }
  367.     }
  368.  
  369.     // and update the disk with any unwritten data
  370.     FlushVol( nil, pFileSpec->vRefNum );
  371.  
  372.     return err;
  373. }
  374.  
  375.  
  376. /*    The following 2 functions (CheckObjectLock and FSpCheckObjectLock) were taken
  377.     from MoreFiles 1.2.1, a code sample from Apple's DTS.  Here's some info from
  378.     the MoreFiles readme:
  379.  
  380.         A collection of File Manager and related routines
  381.  
  382.         by Jim Luther, Apple Macintosh Developer Technical Support
  383.         with significant code contributions by Nitin Ganatra, Apple Macintosh Developer
  384.         Technical Support
  385.         MoreFile Reference is by Eric Soldan
  386.         Copyright © 1992-1994 Apple Computer, Inc.
  387.         All rights reserved.
  388.  
  389.     Frankly, this is one amazing repository of all sorts of file-related things.  I'd
  390.     check it out if you can. (should be, as of this writing, on ftp.info.apple.com
  391.     in like the /Apple.Support.Services/Developer_Support/ or something like that).
  392.  
  393.     thanx to Alex Rosen for answering my post on comp.sys.mac.programmer.help and pointing
  394.     out MoreFiles to me.
  395.  
  396.     WHAT DO THEY DO?  Oh duh...i should tell you huh?
  397.  
  398.     Both functions do the same thing:  check to see if the object is locked
  399.     (in this case, the object is a file).  This is using in WriteTextFile()
  400.     to prevent overwriting/deleting locked files.
  401.  
  402.     The only difference between these 2 functions are the arguments passed.
  403.     the first takes a vRefNum, dirID and a file name, the second takes an FSSpec
  404.     and then just calls the first based on the FSSpec (just makes for slighly
  405.     neater/readable code)
  406. */
  407.  
  408. pascal    OSErr    CheckObjectLock(short vRefNum, long dirID, StringPtr name)
  409. {
  410.     CInfoPBRec pb;
  411.     OSErr error;
  412.  
  413.     pb.hFileInfo.ioNamePtr = name;
  414.     pb.hFileInfo.ioVRefNum = vRefNum;
  415.     pb.hFileInfo.ioDirID = dirID;
  416.     pb.hFileInfo.ioFDirIndex = 0;    // use ioNamePtr and ioDirID
  417.     error = PBGetCatInfoSync(&pb);
  418.  
  419.     if ( error == noErr )
  420.     {
  421.         // check locked bit
  422.         if ( (pb.hFileInfo.ioFlAttrib & 0x01) != 0 )
  423.             error = fLckdErr;
  424.     }
  425.     return ( error );
  426. }
  427.  
  428. /*****************************************************************************/
  429.  
  430. pascal    OSErr    FSpCheckObjectLock(const FSSpec *spec)
  431. {
  432.     return ( CheckObjectLock(spec->vRefNum, spec->parID, (StringPtr) spec->name) );
  433. }
  434.  
  435.